package com.bblocks.common.anti_reptile.captcha;

import com.bblocks.common.anti_reptile.constant.AntiReptileConsts;
import com.bblocks.common.anti_reptile.constant.RuleResultEnum;
import com.bblocks.common.anti_reptile.rule.RuleActuator;
import com.bblocks.common.anti_reptile.util.StrUtil;
import io.springboot.captcha.ArithmeticCaptcha;
import io.springboot.captcha.SpecCaptcha;
import io.springboot.captcha.base.Captcha;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>Project: bb-anti-reptile - CaptchaController</p>
 * <p>描述：验证码</p>
 *
 * @Author Zhao [125043150@qq.com]
 * @Date 2024/4/17 9:34
 * @Version 1.0
 * @since 8
 */
@Slf4j
@RequestMapping("/antireptile/captcha")
public class CaptchaController {
    /**
     * redis种key前缀
     */
    private final String CAPTCHA_KEY_PRE = AntiReptileConsts.BB_ANTI_PRE + "captcha::";

    /**
     * 分钟
     */
    @Value("${anti.reptile.captcha.timeout:10}")
    private Integer captchaTimeout;

    /**
     * 定义响应
     */
    @Value("${anti.reptile.captcha.codeName:code}")
    private String codeName;

    @Value("${anti.reptile.captcha.msgName:msg}")
    private String msgName;

    @Value("${anti.reptile.captcha.dataName:data}")
    private String dataName;

    /**
     * 成功code码，
     * 如果定义0=成功，则失败会返回1，否则反过来
     */
    @Value("${anti.reptile.captcha.codeSuc:1}")
    private Integer sucCode;

    @Lazy
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private RuleActuator ruleActuator;

    /**
     *  返回验证码，格式data=《 verKey=xx,image=base64》
     * @return
     * @throws Exception
     */
    @ResponseBody
    @PostMapping("/one")
    public Map captcha() throws Exception {
        // 三个参数分别为宽、高、位数
        Captcha captcha = buildCaptcha();

        // 验证码存入redis
        String verCode = captcha.text().toLowerCase();
        //log.info("verCode:{}",verCode);
        String key = UUID.randomUUID().toString();
        redissonClient.getBucket(CAPTCHA_KEY_PRE + key).set(verCode,captchaTimeout, TimeUnit.MINUTES);

        // 将key和base64返回给前端
        Map data = new HashMap(2);
        data.put("verKey", key);
        data.put("image", captcha.toBase64());
        return buildResult(true,null,data);
    }

    /**
     * 校验验证码，验证码通过清除验证码限流
     * @param verKey
     * @param verCode
     * @return
     */
    @ResponseBody
    @PostMapping("/verify")
    public Map captchaVerify(String verKey,String verCode,HttpServletRequest request){
        Assert.notNull(verKey, "verKey不能为空");
        Assert.notNull(verCode, "verCode不能为空");

        String verCodeRedis = (String)redissonClient.getBucket(CAPTCHA_KEY_PRE + verKey).get();
        if(StrUtil.isEmpty(verCodeRedis)){
            return buildResult(false,"验证码已过期",null);
        }
        // 判断验证码（验证失败是否需要清理掉验证码？）
        if ( !verCodeRedis.equalsIgnoreCase(verCode.trim())) {
            return buildResult(false,"验证码不正确",null);
        }
        redissonClient.getBucket(CAPTCHA_KEY_PRE + verKey).delete();
        //解锁验证码限流
        ruleActuator.reset(request,null, RuleResultEnum.RATELIMIT_CAPTCHA);
        return buildResult(true,"验证成功",null);
    }

    /**
     * 测试用生成验证码图片
     * @param request
     * @param response
     * @throws Exception
     */
    //@GetMapping("/test")
    public void captchaTest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 设置请求头为输出图片类型
        response.setContentType("image/gif");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);

        Captcha captcha = buildCaptcha();
        // 验证码存入session
        request.getSession().setAttribute("captcha", captcha.text().toLowerCase());
        // 输出图片流
        captcha.out(response.getOutputStream());
    }

    /**
     * 生成验证码
     * 更多验证码见：https://github.com/pig-mesh/easy-captcha
     * @return
     */
    private Captcha buildCaptcha(){
        // 算术类型
        ArithmeticCaptcha captcha = new ArithmeticCaptcha(130, 48);
        captcha.setLen(2);  // 几个数运算，默认是两个
        captcha.getArithmeticString();  // 获取运算的公式：3+2=?
        captcha.text();  // 获取运算的结果：5
        captcha.supportAlgorithmSign(4); // 可设置支持的算法：2=+法，3=+-法，4=+-*
        captcha.setDifficulty(10); // 设置计算难度，参与计算的每一个整数的最大值
        return captcha;
    }

    /**
     * 生成响应
     */
    private Map<String, Object> buildResult(boolean suc, String msg, Object data) {
        int code = 0;
        if(suc){
            code = sucCode;
            if(StrUtil.isEmpty(msg))
                msg = "成功";
        }else{
            if(sucCode == 0){
                code = 1;
            }else{
                code = 0;
            }
        }
        Map<String, Object> map = new HashMap<>(4);
        map.put(codeName, code);
        map.put(msgName, msg);
        if(data != null)
            map.put(dataName, data);
        return map;
    }
}
